<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>xeokit Example</title>
    <link href="../css/pageStyle.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>

    <style>

        .viewer-ruler-wire-highlighted {
            border: 2px solid white !important;
        }

        .viewer-ruler-label-highlighted {
            border: 2px solid white !important;
        }

        .viewer-ruler-dot-highlighted {
            border: 2px solid white !important;
        }

        .xeokit-context-menu {
            font-family: 'Roboto', sans-serif;
            font-size: 15px;
            display: none;
            z-index: 300000;
            background: rgba(255, 255, 255, 0.46);
            border: 1px solid black;
            border-radius: 6px;
            padding: 0;
            width: 200px;
        }

        .xeokit-context-menu ul {
            list-style: none;
            margin-left: 0;
            padding: 0;
        }

        .xeokit-context-menu-item {
            list-style-type: none;
            padding-left: 10px;
            padding-right: 20px;
            padding-top: 4px;
            padding-bottom: 4px;
            color: black;
            background: rgba(255, 255, 255, 0.46);
            cursor: pointer;
            width: calc(100% - 30px);
        }

        .xeokit-context-menu-item:hover {
            background: black;
            color: white;
            font-weight: normal;
        }

        .xeokit-context-menu-item span {
            display: inline-block;
        }

        .xeokit-context-menu .disabled {
            display: inline-block;
            color: gray;
            cursor: default;
            font-weight: normal;
        }

        .xeokit-context-menu .disabled:hover {
            color: gray;
            cursor: default;
            background: #eeeeee;
            font-weight: normal;
        }

        .xeokit-context-menu-item-separator {
            background: rgba(0, 0, 0, 1);
            height: 1px;
            width: 100%;
        }

        

    </style>
</head>
<body>
<input type="checkbox" id="info-button"/>
<label for="info-button" class="info-button"><i class="far fa-3x fa-question-circle"></i></label>
<canvas id="myCanvas"></canvas>
<div class="slideout-sidebar">
    <img class="info-icon" src="../../assets/images/measure_distance_icon.png"/>
    <h1>DistanceMeasurementPlugin with DistanceMeasurementsMouseControl and PointerLens</h1>
    <h2>Click on the model to create distance measurements, with vertex and edge snapping</h2>
    <p>In this example, we're loading a BIM model from the file system, then creating distance measurements wherever the
        user clicks on the model with the mouse.</p>
    <h3>Components Used</h3>
    <ul>
        <li>
            <a href="../../docs/class/src/viewer/Viewer.js~Viewer.html"
               target="_other">Viewer</a>
        </li>
        <li>
            <a href="../../docs/class/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsPlugin.js~DistanceMeasurementsPlugin.html"
               target="_other">DistanceMeasurementsPlugin</a>
        </li>
        <li>
            <a href="../../docs/class/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsMouseControl.js~DistanceMeasurementsMouseControl.html"
               target="_other">DistanceMeasurementsMouseControl</a>
        </li>
        <li>
            <a href="../../docs/class/src/extras/PointerLens/PointerLens.js~PointerLens.html"
               target="_other">PointerLens</a>
        </li>
        <li>
            <a href="../../docs/class/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js~XKTLoaderPlugin.html"
               target="_other">XKTLoaderPlugin</a>
        </li>
    </ul>
    <h3>Tutorials</h3>
    <ul>
        <li>
            <a href="https://www.notion.so/xeokit/Accurate-Measurements-with-Snapping-5e6606afef20428f9b319ea0e82270f9"
               target="_other">Accurate Measurements with Snapping</a>
        </li>
    </ul>
    <h3>Assets</h3>
    <ul>
        <li>
            <a href="http://openifcmodel.cs.auckland.ac.nz/Model/Details/274"
               target="_other">Model source</a>
        </li>
    </ul>
</div>
</body>
<script type="module">

    //------------------------------------------------------------------------------------------------------------------
    // Import the modules we need for this example
    //------------------------------------------------------------------------------------------------------------------

    import {Viewer, XKTLoaderPlugin, ContextMenu, PointerLens, DistanceMeasurementsPlugin, DistanceMeasurementsMouseControl, DistanceMeasurementEditMouseControl} from "../../dist/xeokit-sdk.es.js";
    
    //------------------------------------------------------------------------------------------------------------------
    // Create a Viewer and arrange the camera
    //------------------------------------------------------------------------------------------------------------------

    const viewer = new Viewer({
        canvasId: "myCanvas",
        dtxEnabled: true
    });

    viewer.camera.eye = [-3.93, 2.85, 27.01];
    viewer.camera.look = [4.40, 3.72, 8.89];
    viewer.camera.up = [-0.01, 0.99, 0.039];

    viewer.cameraControl.panRightClick = false; // Prevents right-click-drag panning interfering with ContextMenus

    //------------------------------------------------------------------------------------------------------------------
    // Load a model
    //------------------------------------------------------------------------------------------------------------------

    const xktLoader = new XKTLoaderPlugin(viewer);

    const sceneModel = xktLoader.load({
        id: "myModel",
        src: "../../assets/models/xkt/v10/glTF-Embedded/Duplex_A_20110505.glTFEmbedded.xkt",
        edges: true
    });

    sceneModel.on("loaded", () => {
        viewer.cameraFlight.jumpTo(sceneModel);
    });

    //------------------------------------------------------------------------------------------------------------------
    // DistanceMeasurementsPlugin, DistanceMeasurementsMouseControl and PointerLens
    //------------------------------------------------------------------------------------------------------------------

    const distanceMeasurementsPlugin = new DistanceMeasurementsPlugin(viewer);

    distanceMeasurementsPlugin.on("measurementStart", (distanceMeasurement) => {
        console.log("measurementStart");
        console.log("origin", distanceMeasurement.origin.entity);
        console.log("target", distanceMeasurement.target.entity);
    });

    distanceMeasurementsPlugin.on("measurementEnd", (distanceMeasurement) => {
        console.log("measurementEnd");
        console.log("origin", distanceMeasurement.origin.entity);
        console.log("target", distanceMeasurement.target.entity);
    });

    distanceMeasurementsPlugin.on("measurementCancel", (distanceMeasurement) => {
        console.log("measurementCancel");
        console.log("origin", distanceMeasurement.origin.entity);
        console.log("target", distanceMeasurement.target.entity);
    });

    const distanceMeasurementsMouseControl = new DistanceMeasurementsMouseControl(distanceMeasurementsPlugin, {
        pointerLens: new PointerLens(viewer),
        snapping: true // Default
    })

    distanceMeasurementsMouseControl.snapping = true;

    distanceMeasurementsMouseControl.activate();

    //------------------------------------------------------------------------------------------------------------------
    // Create a context menu to delete and configure measurements
    //------------------------------------------------------------------------------------------------------------------

    let endMeasurementEdit = null;

    const distanceMeasurementsContextMenu = new ContextMenu({
        items: [
            [
                {
                    title: "Clear",
                    doAction: function (context) {
                        context.distanceMeasurement.destroy();
                    }
                },
                {
                    getTitle: (context) => {
                        return context.distanceMeasurement.axisVisible ? "Hide Axis" : "Show Axis";
                    },
                    doAction: function (context) {
                        context.distanceMeasurement.axisVisible = !context.distanceMeasurement.axisVisible;
                    }
                },
                {
                    getTitle: (context) => {
                        return context.distanceMeasurement.xLabelEnabled && context.distanceMeasurement.labelsVisible ? "Disable X Label" : "Enable X Label";
                    },
                    doAction: function (context) {
                        context.distanceMeasurement.xLabelEnabled = !context.distanceMeasurement.xLabelEnabled;
                    }
                },
                {
                    getTitle: (context) => {
                        return context.distanceMeasurement.yLabelEnabled && context.distanceMeasurement.labelsVisible ? "Disable Y Label" : "Enable Y Label";
                    },
                    doAction: function (context) {
                        context.distanceMeasurement.yLabelEnabled = !context.distanceMeasurement.yLabelEnabled;
                    }
                },
                {
                    getTitle: (context) => {
                        return context.distanceMeasurement.zLabelEnabled && context.distanceMeasurement.labelsVisible ? "Disable Z Label" : "Enable Z Label";
                    },
                    doAction: function (context) {
                        context.distanceMeasurement.zLabelEnabled = !context.distanceMeasurement.zLabelEnabled;
                    }
                },
                {
                    getTitle: (context) => {
                        return context.distanceMeasurement.lengthLabelEnabled && context.distanceMeasurement.labelsVisible ? "Disable Length Label" : "Enable Length Label";
                    },
                    doAction: function (context) {
                        context.distanceMeasurement.lengthLabelEnabled = !context.distanceMeasurement.lengthLabelEnabled;
                    }
                },
                {
                    getTitle: (context) => {
                        return context.distanceMeasurement.labelsVisible ? "Hide All Labels" : "Show All Labels";
                    },
                    doAction: function (context) {
                        context.distanceMeasurement.labelsVisible = !context.distanceMeasurement.labelsVisible;
                    }
                },
                {
                    title: "Edit",
                    doAction: function (context) {
                        distanceMeasurementsMouseControl.deactivate();
                        const measurement = context.distanceMeasurement;
                        const edit = new DistanceMeasurementEditMouseControl(measurement, {
                            pointerLens: new PointerLens(viewer),
                            snapping: true
                        });
                        edit.on("edited", () => console.log("edited", measurement.id));
                        endMeasurementEdit = () => {
                            edit.deactivate();
                            endMeasurementEdit = null;
                        };
                    }
                }
            ], [
                {
                    title: "Clear All",
                    getEnabled: function (context) {
                        return (Object.keys(context.distanceMeasurementsPlugin.measurements).length > 0);
                    },
                    doAction: function (context) {
                        context.distanceMeasurementsPlugin.clear();
                    }
                },
                {
                    getTitle: () => {
                        return "Cancel Measurement";
                    },
                    doAction: function () {
                        distanceMeasurementsMouseControl.reset();
                    }
                }
            ]
        ]
    });

    distanceMeasurementsContextMenu.on("hidden", () => {
        if (distanceMeasurementsContextMenu.context.distanceMeasurement) {
            distanceMeasurementsContextMenu.context.distanceMeasurement.setHighlighted(false);
        }
    });

    //------------------------------------------------------------------------------------------------------------------
    // Create a context menu to activate and deactivate the control
    //------------------------------------------------------------------------------------------------------------------

    const canvasContextMenu = new ContextMenu({
        enabled: true,
        context: {
            viewer: viewer
        },
        items: [
            [
                {
                    getTitle: (context) => {
                        return distanceMeasurementsMouseControl.active ? "Deactivate Control" : "Activate Control";
                    },
                    doAction: function (context) {
                        distanceMeasurementsMouseControl.active
                            ? distanceMeasurementsMouseControl.deactivate()
                            : distanceMeasurementsMouseControl.activate();
                    }
                },
                {
                    getTitle: () => {
                        return "Cancel Measurement";
                    },
                    getEnabled: function () {
                        return (!!distanceMeasurementsMouseControl.currentMeasurement);
                    },
                    doAction: function () {
                        distanceMeasurementsMouseControl.reset();
                    }
                },
                {
                    getTitle: () => {
                        return "End Editing";
                    },
                    getEnabled: function () {
                        return !!endMeasurementEdit;
                    },
                    doAction: function () {
                        endMeasurementEdit();
                    }
                }
            ]
        ]
    });

    viewer.scene.canvas.canvas.addEventListener('contextmenu', (event) => {
        const canvasPos = getCanvasPosFromEvent(event);
        console.log("canvas context menu")
        canvasContextMenu.show(canvasPos[0], canvasPos[1]);
        event.preventDefault();
        event.stopPropagation();
    });

    //------------------------------------------------------------------------------------------------------------------
    // Create an DistanceMeasurementsPlugin, activate its DistanceMeasuremntsControl
    //------------------------------------------------------------------------------------------------------------------

    distanceMeasurementsPlugin.on("mouseOver", (e) => {
        if (endMeasurementEdit) {
            return;
        }
        e.distanceMeasurement.setHighlighted(true);
    });

    distanceMeasurementsPlugin.on("mouseLeave", (e) => {
        if (endMeasurementEdit) {
            return;
        }
        if (distanceMeasurementsContextMenu.shown && distanceMeasurementsContextMenu.context.distanceMeasurement.id === e.distanceMeasurement.id) {
            return;
        }
        e.distanceMeasurement.setHighlighted(false);
    });

    distanceMeasurementsPlugin.on("contextMenu", (e) => {
        if (endMeasurementEdit) {
            return;
        }
        distanceMeasurementsContextMenu.context = { // Must set context before showing menu
            viewer: viewer,
            distanceMeasurementsPlugin: distanceMeasurementsPlugin,
            distanceMeasurement: e.distanceMeasurement
        };
        distanceMeasurementsContextMenu.show(e.event.clientX, e.event.clientY);
        e.event.preventDefault();
    });

    const getCanvasPosFromEvent = function (event) {
        const canvasPos = [];
        if (!event) {
            event = window.event;
            canvasPos[0] = event.x;
            canvasPos[1] = event.y;
        } else {
            let element = event.target;
            let totalOffsetLeft = 0;
            let totalOffsetTop = 0;
            let totalScrollX = 0;
            let totalScrollY = 0;
            while (element.offsetParent) {
                totalOffsetLeft += element.offsetLeft;
                totalOffsetTop += element.offsetTop;
                totalScrollX += element.scrollLeft;
                totalScrollY += element.scrollTop;
                element = element.offsetParent;
            }
            canvasPos[0] = event.pageX + totalScrollX - totalOffsetLeft;
            canvasPos[1] = event.pageY + totalScrollY - totalOffsetTop;
        }
        return canvasPos;
    };

    window.viewer = viewer;

</script>
</html>